import json
from pathlib import Path
from typing import Dict, List, Any, Tuple
import random
import spacy
from sklearn.metrics.pairwise import cosine_similarity
import numpy as np
import logging
from datetime import datetime
from dataclasses import dataclass
from knowledge_graph import JobKnowledgeGraph

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("InterviewAssistant")

# 加载NLP模型
nlp = spacy.load("zh_core_web_sm")

@dataclass
class InterviewQuestion:
    """面试问题数据类"""
    question_id: str
    question_text: str
    question_type: str  # technical/behavioral/situational
    reference_answer: str
    key_points: List[str]
    difficulty: str  # easy/medium/hard

@dataclass
class InterviewEvaluation:
    """面试评估数据类"""
    question_id: str
    answer_similarity: float
    covered_points: List[str]
    missing_points: List[str]
    feedback: str
    score: float

class InterviewAssistant:
    """智能面试助手"""
    def __init__(self, kg_client: JobKnowledgeGraph = None):
        self.kg = kg_client
        self.questions_db = Path("b/data/interview_questions")
        self._init_question_db()
        self.question_embeddings = {}
        self._load_questions()
        
    def _init_question_db(self):
        """初始化问题数据库"""
        self.questions_db.mkdir(parents=True, exist_ok=True)
        
        # 创建示例问题库 (如果不存在)
        sample_files = {
            "technical.json": {
                "Python开发工程师": [
                    {
                        "question": "请解释Python中的装饰器原理及应用场景",
                        "type": "technical",
                        "reference": "装饰器是修改函数或类的功能的一种方式...",
                        "key_points": ["函数作为对象", "闭包概念", "@语法糖"],
                        "difficulty": "medium"
                    }
                ]
            },
            "behavioral.json": {
                "通用行为问题": [
                    {
                        "question": "请描述你遇到过的技术挑战及如何解决的",
                        "type": "behavioral",
                        "reference": "在XX项目中遇到XX问题...",
                        "key_points": ["问题描述", "解决过程", "学习收获"],
                        "difficulty": "medium"
                    }
                ]
            }
        }
        
        for filename, content in sample_files.items():
            if not (self.questions_db / filename).exists():
                with open(self.questions_db / filename, "w", encoding="utf-8") as f:
                    json.dump(content, f, ensure_ascii=False, indent=2)
                logger.info(f"已创建示例问题文件: {filename}")
    
    def _load_questions(self):
        """加载问题并预处理嵌入"""
        self.questions = []
        for q_file in self.questions_db.glob("*.json"):
            with open(q_file, "r", encoding="utf-8") as f:
                for job_title, q_list in json.load(f).items():
                    for q in q_list:
                        question = InterviewQuestion(
                            question_id=f"{job_title}_{len(self.questions)}",
                            question_text=q["question"],
                            question_type=q["type"],
                            reference_answer=q["reference"],
                            key_points=q["key_points"],
                            difficulty=q.get("difficulty", "medium")
                        )
                        self.questions.append(question)
                        
                        # 预计算问题嵌入
                        doc = nlp(question.question_text)
                        self.question_embeddings[question.question_id] = doc.vector
        
        logger.info(f"已加载 {len(self.questions)} 个面试问题")
    
    def generate_interview(self, job_title: str, difficulty: str = "medium", 
                          num_questions: int = 5) -> List[InterviewQuestion]:
        """生成面试问题列表"""
        # 从知识图谱获取相关技能
        if self.kg:
            related_skills = self.kg.find_skills_for_job(job_title)
        else:
            related_skills = []
        
        # 筛选相关问题
        candidate_questions = []
        for q in self.questions:
            # 匹配岗位标题或技能关键词
            title_match = job_title.lower() in q.question_id.lower()
            skill_match = any(skill.lower() in q.question_text.lower() 
                             for skill in related_skills)
            
            # 匹配难度
            diff_match = q.difficulty == difficulty
            
            if (title_match or skill_match) and diff_match:
                candidate_questions.append(q)
        
        # 随机选择问题
        selected = random.sample(
            candidate_questions, 
            min(num_questions, len(candidate_questions))
        )
        
        logger.info(f"为岗位 '{job_title}' 生成 {len(selected)} 个面试问题")
        return selected
    
    def evaluate_answer(self, question: InterviewQuestion, 
                       user_answer: str) -> InterviewEvaluation:
        """评估用户回答"""
        # 计算回答与参考答案的相似度
        ref_doc = nlp(question.reference_answer)
        user_doc = nlp(user_answer)
        
        similarity = cosine_similarity(
            [ref_doc.vector], 
            [user_doc.vector]
        )[0][0]
        
        # 检查关键点覆盖情况
        covered = []
        missing = []
        for point in question.key_points:
            if any(token.text in user_answer for token in nlp(point)):
                covered.append(point)
            else:
                missing.append(point)
        
        # 生成反馈
        feedback = self._generate_feedback(
            similarity, 
            len(covered), 
            len(question.key_points)
        )
        
        # 计算分数 (0-100)
        score = min(100, max(0, 
            (similarity * 40) +  # 内容相似度
            (len(covered) / len(question.key_points) * 60)  # 关键点覆盖
        ))
        
        return InterviewEvaluation(
            question_id=question.question_id,
            answer_similarity=similarity,
            covered_points=covered,
            missing_points=missing,
            feedback=feedback,
            score=round(score, 1)
        )
    
    def _generate_feedback(self, similarity: float, 
                         covered: int, total_points: int) -> str:
        """生成反馈文本"""
        # 相似度反馈
        if similarity > 0.7:
            sim_feedback = "回答与参考答案高度一致"
        elif similarity > 0.4:
            sim_feedback = "回答与参考答案部分一致"
        else:
            sim_feedback = "回答与参考答案差异较大"
        
        # 关键点反馈
        coverage = covered / total_points
        if coverage > 0.8:
            point_feedback = "涵盖了大部分关键点"
        elif coverage > 0.5:
            point_feedback = "涵盖了一部分关键点"
        else:
            point_feedback = "遗漏了多数关键点"
        
        # 改进建议
        if coverage < 0.5:
            suggestion = "建议更系统地组织答案，确保覆盖所有关键点"
        elif similarity < 0.4:
            suggestion = "建议更准确地理解问题核心，提供更相关的回答"
        else:
            suggestion = "回答良好，可以进一步举例说明以增强说服力"
        
        return f"{sim_feedback}，{point_feedback}。{suggestion}"
    
    def conduct_mock_interview(self, job_title: str, 
                             difficulty: str = "medium") -> Dict[str, Any]:
        """进行模拟面试"""
        questions = self.generate_interview(job_title, difficulty)
        evaluations = []
        total_score = 0
        
        logger.info(f"开始 '{job_title}' 岗位的模拟面试 (难度: {difficulty})")
        
        # 模拟问答过程
        for i, question in enumerate(questions, 1):
            print(f"\n问题 {i}/{len(questions)}: {question.question_text}")
            user_answer = input("请输入你的回答: ")
            
            evaluation = self.evaluate_answer(question, user_answer)
            evaluations.append(evaluation)
            total_score += evaluation.score
            
            print(f"\n反馈: {evaluation.feedback}")
            print(f"得分: {evaluation.score}/100")
            if evaluation.missing_points:
                print(f"遗漏关键点: {', '.join(evaluation.missing_points)}")
        
        # 计算平均分
        avg_score = total_score / len(questions)
        
        # 生成综合报告
        report = {
            "job_title": job_title,
            "difficulty": difficulty,
            "total_questions": len(questions),
            "average_score": round(avg_score, 1),
            "question_breakdown": [
                {
                    "question": q.question_text,
                    "score": e.score,
                    "feedback": e.feedback
                }
                for q, e in zip(questions, evaluations)
            ],
            "overall_feedback": self._generate_overall_feedback(avg_score),
            "timestamp": datetime.now().isoformat()
        }
        
        # 保存报告
        report_file = Path(f"b/data/interview_reports/{job_title}_report.json")
        report_file.parent.mkdir(exist_ok=True)
        with open(report_file, "w", encoding="utf-8") as f:
            json.dump(report, f, ensure_ascii=False, indent=2)
        
        logger.info(f"模拟面试完成，报告已保存到 {report_file}")
        return report
    
    def _generate_overall_feedback(self, score: float) -> str:
        """生成总体反馈"""
        if score >= 80:
            return "表现优秀！已准备好应对实际面试"
        elif score >= 60:
            return "表现良好，某些方面还需改进"
        elif score >= 40:
            return "表现一般，需要系统准备"
        else:
            return "需要加强准备，建议多练习并研究岗位要求"

if __name__ == "__main__":
    # 示例使用
    kg = JobKnowledgeGraph()
    assistant = InterviewAssistant(kg)
    
    # 生成面试问题
    questions = assistant.generate_interview("Python开发工程师")
    print("\n生成的面试问题:")
    for i, q in enumerate(questions, 1):
        print(f"{i}. {q.question_text} ({q.question_type}, {q.difficulty})")
    
    # 评估示例回答
    sample_answer = "装饰器是用来修改函数行为的函数，使用@符号调用"
    evaluation = assistant.evaluate_answer(questions[0], sample_answer)
    print(f"\n回答评估: {evaluation.score}/100")
    print(f"反馈: {evaluation.feedback}")
    
    # 进行模拟面试 (取消注释以运行)
    # assistant.conduct_mock_interview("Python开发工程师")